package com.xiang.WebSocket;

import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import jakarta.websocket.EndpointConfig;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;

import com.xiang.api.Util;
import com.xiang.api.entity.Message;
import com.xiang.sql.StaticService;
import com.xiang.sql.entity.User;

import org.springframework.stereotype.Component;

import lombok.Data;

@Data
@ServerEndpoint(value = "/{token}", configurator = WebSocketConfig.class)
@Component
public class MyWebSocket {
  private RecvManage recvManage;

  public Session session;

  public User user;
  public String ip;

  private final Lock lock = new ReentrantLock();
  private WebSocketService ws;

  @OnOpen
  public void onOpen(Session session, @PathParam("token") String token,
      EndpointConfig endpointConfig) throws Exception {
    this.session = session;
    this.ip = (String) endpointConfig.getUserProperties().get(WebSocketConfig.IP);
    try {
      token = new URI(token).getPath();
    } catch (Exception e) {
      token = null;
    }
    if (token == null) {
      close();
      return;
    }
    try {
      this.user = StaticService.user.getByToken(token);
    } catch (Exception e) {
      this.user = null;
    }
    if (this.user == null) {
      close();
      return;
    }
    user.password = null;
    if (ws == null) {
      ws = Util.applicationContext.getBean(WebSocketService.class);
    }
    ws.addWebSocket(this);

    recvManage = new RecvManage(this);
  }

  @OnClose
  public void close() {
    try {
      this.session.getAsyncRemote().sendText("{\"data\":\"非法连接\"}");
    } catch (Exception e) {
    }
    try {
      this.session.close();
    } catch (Exception e) {
    }
    if (this.user == null) {
      if (this.session != null) {
        this.session = null;
        // log.warn("非法连接: " + ip);
      }
    } else {
      this.user = null;
      ws.removeWebSocket(this);
    }
  }

  @OnMessage
  public void onMessage(String message, Session session) {
    if (user == null) {
      close();
      try {
        session.close();
      } catch (Exception e) {
      }
      return;
    }
    try {
      send(recvManage.recv(message));
    } catch (Exception e) {
      send(new Message(Util.errString(e)));
    }
  }

  @OnMessage
  public void onMessage(byte[] msg, Session session) {
    onMessage(new String(msg, StandardCharsets.UTF_8), session);
  }

  @OnError
  public void onError(Session session, Throwable error) {
    String es = error.getMessage();
    System.out.println("onError输出: " + es);
    if (es.indexOf("断开的管道") < 0) {
      // error.printStackTrace();
    }
  }

  public void send(Object data) {
    if (data != null) {
      synchronized (session) {
        try {
          jakarta.websocket.RemoteEndpoint.Basic b = session.getBasicRemote();
          lock.lock();
          if (data instanceof byte[]) {
            b.sendBinary(ByteBuffer.wrap((byte[]) data));
          } else if (data instanceof String) {
            b.sendText((String) data); // 阻塞
          } else {
            b.sendText(Util.toJString(data)); // 阻塞
            // session.getAsyncRemote().sendText(Util.toJString(data)); // 异步
          }
        } catch (Exception e) {
          // e.printStackTrace();
          // log.info(Util.errString(e));
        } finally {
          lock.unlock();
        }
      }
    }
  }
}